Publishing NuGet Packages with Default Files Using Visual Studio
TLDR
- When developing NuGet packages, it is recommended to prioritize
.NET Standardas the target platform. - Modern
.NETprojects allow you to configure package information directly in the.csprojfile, eliminating the need for a separate.nuspecfile. - To automatically copy configuration files during package installation, the
package.configmode requires aninstall.ps1script, while thePackageReferencemode relies on<Content>settings within the project file. - For
.NET Frameworkprojects usingPackageReference, file copying orinstall.ps1execution may not trigger correctly; compatibility testing is recommended for this scenario.
Fundamentals Before Developing a Package
Choosing a Target Platform
When developing a NuGet package, it is recommended to choose .NET Standard to ensure cross-platform support. If you need to support older .NET Framework versions, you can configure TargetFrameworks in your project file for multi-targeting:
<PropertyGroup>
<TargetFrameworks>netstandard2.1;netstandard2.0;net45</TargetFrameworks>
</PropertyGroup>Editing Package Information
Modern Visual Studio allows you to define NuGet package metadata directly in the .csproj file, replacing the traditional .nuspec file. Key settings include:
- Version: It is recommended to follow SemVer specifications.
- PackageLicenseExpression: If using common licenses like MIT or BSD, please use SPDX license identifiers.
- PackageId: The package name; if not specified, it defaults to the project name.
Publishing NuGet Packages with Files
When including default configuration files (such as Config.json) in a package, you must consider the two primary installation formats: package.config and PackageReference.
File Configuration
To include files in a package and handle them during installation, configure your .csproj as follows:
<ItemGroup>
<Content Include=".\Config.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PackageCopyToOutput>true</PackageCopyToOutput>
</Content>
<None Include=".\install.ps1">
<Pack>True</Pack>
<PackagePath>tools</PackagePath>
</None>
</ItemGroup>Purpose of install.ps1
When does this issue arise? When you use the package.config format to install a package and wish to automatically set file properties (such as Build Action or Copy to Output Directory).
This script is only effective for package.config. An example is provided below:
param($installPath, $toolsPath, $package, $project)
# Set file name
$configItem = $project.ProjectItems.Item("Config.json")
# Set 'Copy To Output Directory' to PreserveNewest (2)
$copyToOutput = $configItem.Properties.Item("CopyToOutputDirectory")
$copyToOutput.Value = 2
# Set 'Build Action' to Content (2)
$buildAction = $configItem.Properties.Item("BuildAction")
$buildAction.Value = 2Validation Results for Different Installation Scenarios
1. .NET Framework with package.config
- Result: Success.
install.ps1executes automatically, and file properties are correctly set to "Content" and "Copy if newer".
2. ASP.NET Core (using PackageReference)
- Result: Partially successful.
install.ps1does not execute, but the file is added to the project, and copy properties generally function as expected.
3. .NET Framework with PackageReference
- Result: Failure. This combination does not execute
install.ps1, and files are typically not automatically copied to the target project. - Recommendation: If your package must support this scenario, it is recommended to advise users in the documentation to add the configuration file manually, or consider providing initialization code instead of relying on automatic copying.
WARNING
NuGet.org only accepts license expressions approved by the Open Source Initiative or the Free Software Foundation.
Change Log
- 2022-11-08 Initial documentation created.